home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / tkern10.zip / GNUISH\_CWILD.C < prev    next >
Text File  |  1994-07-16  |  10KB  |  384 lines

  1. /*  _cwild.c - (reasonable, i.e. **IX style) wildcard expansion and
  2.     passing of long commandlines for MSC
  3.     Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 1, or (at your option)
  8.     any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.     $Header: e:/gnu/lib/RCS/_cwild.c 1.0 90/09/11 01:55:11 tho Exp $
  20.  
  21.     Friday, 15 July, 1994  Troy Rollo (troy@cbme.unsw.EDU.AU)
  22.     - Added type cast to call to qsort()
  23.  
  24.     Saturday, 16 July 1994  Troy Rollo(troy@cbme.unsw.EDU.AU)
  25.     - #ifndef __BORLANDC__'d large chunks - we only really
  26.       want this for msdos_format_filename
  27.  */
  28.  
  29.  
  30. /* One of the major shortcomings of MS-DOS is the inability to pass long
  31.    commandlines.  Commandlines are restricted to 126 characters in length
  32.    and may not contain newlines, etc.
  33.  
  34.    Both of these restrictions make it impossible to put reasonably sized
  35.    `awk', `sed', `perl', etc. scripts into shell scripts.  Also it's
  36.    impossible to put reasonably sized shell script fragments into
  37.    makefiles.
  38.  
  39.    One way to overcome *some* of these problems is to let the user
  40.    commands perform their own globbing.  The second (more satisfactory)
  41.    way is to invent a new scheme for argument passing.
  42.  
  43.    One approach that presents itself, is to pass the arguments via the
  44.    environment.  This is the approach adopted here.  If this code is
  45.    compiled with `-DWANT_LONG_COMMANDLINES' (which is implied by
  46.    `-DSMART_SHELL_ONLY' and `-DSMART_SHELL'), the startup code looks for
  47.    "_argc" in the environment.  If it is found, it is used as a argument
  48.    count and the commandline is taken from "_argv0", "_argv1", ...  The
  49.    MS-DOS commandline is *ignored* in this case!  This is of course only
  50.    useful if your Shell or Make supports this feature.  (GNU make will do
  51.    in the next version.)
  52.  
  53.    The other part of the code uses the GNU globbing library to perform
  54.    globbing of the MS-DOS commandline in a **IX compatible way.
  55.  
  56.    This code has been developped to be used with the startup code of
  57.    Microsoft C.  Compile with one of SMART_SHELL_ONLY, SMART_SHELL, or
  58.    DUMB_SHELL_ONLY.  Link with the `setargv.obj' that came with the
  59.    compiler to ensure that _cwild () is called during startup.
  60.  
  61.    IMPORTANT:  Since we want this appraoch to become compiler independent,
  62.    feedback in form of patches for other compilers (Turbo C, Zortech,
  63.    etc.) is *greatly* appreciated.  */
  64.  
  65.  
  66. /* NOTE:  Even though this approach is almost evident, I do *not* put it
  67.    in the public domain.  I CLAIM A COPYRIGHT BOTH ON THIS CODE AND THE
  68.    UNDERLYING IDEAS.  But you are welcome to redistribute, use and
  69.    improve it under the terms of the GNU GENERAL PUBLIC LICENSE.
  70.  
  71.    This seems appropriate in the days of aggressive copyright lawsuits
  72.    to prevent someone from preventing YOU to use it.  */
  73.  
  74.  
  75. /* Configuration Section:  */
  76.  
  77. /* Define this if you are exclusively using Bash, GNU make,
  78.    or other winning utilities which take the load of expanding
  79.    the commandline from your program and know how to pass
  80.    *long* commandlines.  */
  81.  
  82. #ifdef SMART_SHELL_ONLY
  83.  
  84. #ifndef WANT_LONG_COMMANDLINES
  85. #define WANT_LONG_COMMANDLINES
  86. #endif
  87.  
  88. #ifdef WANT_GLOBBING
  89. #undef WANT_GLOBBING
  90. #endif
  91.  
  92. #endif /* SMART_SHELL_ONLY */
  93.  
  94.  
  95. /* Define this if you are always use loosing Shells and Makes, that don't
  96.    know how to pass long commandlines.   And if your program has to expand
  97.    the commandline itself.  */
  98.  
  99. #ifdef DUMB_SHELL_ONLY
  100.  
  101. #ifdef WANT_LONG_COMMANDLINES
  102. #undef WANT_LONG_COMMANDLINES
  103. #endif
  104.  
  105. #ifndef WANT_GLOBBING
  106. #define WANT_GLOBBING
  107. #endif
  108.  
  109. #endif /* not DUMB_SHELL_ONLY */
  110.  
  111.  
  112. #if !defined(SMART_SHELL) && !defined(SMART_SHELL_ONLY) \
  113.   && !defined(DUMB_SHELL_ONLY)
  114. #define SMART_SHELL
  115. #endif
  116.  
  117. /* Define this if your program can expect long commandlines, but should
  118.    also be able to do some globbing. */
  119.  
  120. #ifdef SMART_SHELL
  121.  
  122. #ifndef WANT_LONG_COMMANDLINES
  123. #define WANT_LONG_COMMANDLINES
  124. #endif
  125.  
  126. #ifndef WANT_GLOBBING
  127. #define WANT_GLOBBING
  128. #endif
  129.  
  130. #endif /* SMART_SHELL */
  131.  
  132.  
  133. /* This code relies on the standard GNU globbing library, which does
  134.    all the hard work.  */
  135.  
  136. /* This wildcard expansion module is tailored for use with the Microsoft
  137.    C startup code and uses their conventions.  It will probably not work
  138.    with the libraries of other compilers.  */
  139.  
  140. #include <stdio.h>
  141. #include <stdlib.h>
  142. #include <string.h>
  143. #include <ctype.h>
  144.  
  145. #ifndef __BORLANDC__
  146.  
  147. #ifdef WANT_LONG_COMMANDLINES
  148. static int _cenv (void);
  149. #define LONG_ARGS_PRESENT    (getenv ("_argc") != NULL)
  150. #else
  151. #define _cenv()            1
  152. #define LONG_ARGS_PRESENT    0
  153. #endif
  154.  
  155.  
  156. #ifdef WANT_GLOBBING
  157. #include <gnulib.h>
  158. static int compare (char **s1, char **s2);
  159. static int _cglob (void);
  160. #else
  161. #define _cglob()        1
  162. #endif
  163.  
  164. int _cwild (void);
  165.  
  166.  
  167.  
  168. /* The external argument vector:  */
  169.  
  170. extern int __argc;
  171. extern char ** __argv;
  172.  
  173.  
  174. /* This is the main entry point, decide whether we have a smart shell
  175.    or have to do the globbing ourselves.  */
  176.  
  177. int
  178. _cwild (void)
  179. {
  180.   return LONG_ARGS_PRESENT ? _cenv () : _cglob ();
  181. }
  182.  
  183.  
  184. #ifdef WANT_LONG_COMMANDLINES
  185.  
  186. /* We have been called by a smart shell, get arguments from the
  187.    environment entries "_argc", "_argv0", "_argv1", ...  */
  188.  
  189. int
  190. _cenv (void)
  191. {
  192.   int ind = 0;
  193.   char **argv;
  194.  
  195.   /* We know that "_argc" is there! */
  196.  
  197.   __argc = atoi (getenv ("_argc"));
  198.   if (__argc == 0)
  199.     return -1;
  200.  
  201.   argv = (char **) malloc ((__argc + 1) * sizeof (char *));
  202.   if (argv == NULL)
  203.     return -1;
  204.  
  205.   while (ind < __argc)
  206.     {
  207.       char entry[10];
  208.       char *p;
  209.  
  210.       sprintf (entry, "_argv%d", ind);
  211.       p = getenv (entry);
  212.       if (p != 0)
  213.     argv[ind] = strcpy (malloc (strlen (p) + 1), p);
  214.       else
  215.     argv[ind] = strcpy (malloc (1), "");
  216.  
  217.       ind++;
  218.     }
  219.  
  220.   /* Terminate  */
  221.   argv[__argc] = NULL;
  222.  
  223.   /* Install  */
  224.   __argv = argv;
  225.  
  226.   return 0;
  227. }
  228.  
  229. #endif /* WANT_LONG_COMMANDLINES */
  230.  
  231.  
  232. #ifdef WANT_GLOBBING
  233.  
  234. /* During startup, perform filename globbing of __ARGV.  By Microsoft
  235.    convention, the first letter of each member of __ARGV marks wether
  236.    globbing is to be performed for this specific name.  If it is '\"',
  237.    the string is left alone.  One has to be careful, not to include
  238.    this character in the result.  */
  239.  
  240. int
  241. _cglob (void)
  242. {
  243.   int argc = __argc;
  244.   char **argv = __argv;
  245.   int optind;
  246.  
  247.  
  248.   /* Vector of vectors of globbed filenames, terminated by NULL.
  249.      If GLOB_ARGV[N] == -1, or if *(GLOB_ARGV[N]) == NULL, no
  250.      globbing has been performed and the original __ARGV[N] will
  251.      be used. (Strictly speaking, GLOB_ARGVV[0] is never used,
  252.      but we don't care.) */
  253.  
  254.   char ***glob_argvv = (char ***) malloc (argc * sizeof (char **));
  255.  
  256.   if (glob_argvv == NULL)
  257.     return -1;
  258.  
  259.   __argc = 2;            /* program name and terminating NULL */
  260.  
  261.  
  262.   /* Pass 1: Find out how much storage we need and allocate it.  */
  263.  
  264.   for (optind = 1; optind < argc; optind++)
  265.     {
  266.       /* there's at least one (the original argv[optind]).  */
  267.  
  268.       __argc++;
  269.  
  270.       if (*(argv[optind])++ == '\"')
  271.     {
  272.       /* Don't glob ARGV[OPTIND], but strip the leading quote marker  */
  273.  
  274.       glob_argvv[optind] = (char **) -1;
  275.     }
  276.       else
  277.     {
  278.       char **ptr = glob_argvv[optind]  = glob_filename (argv[optind]);
  279.       size_t cnt = 0;
  280.  
  281.       /* we will ignore errors from glob_filename () and pass the
  282.          unexpanded argument  */
  283.  
  284.       if (ptr != (char **) -1 && *ptr++ != NULL)
  285.         while (*ptr++ != NULL)
  286.           cnt++;
  287.  
  288.       /* Sort the globbed filenames */
  289.  
  290.       if (cnt > 0)
  291.         qsort (glob_argvv[optind], cnt + 1,
  292.            sizeof (char *),
  293.            (int (*)(void const *, void const *)) compare);
  294.  
  295.       __argc += cnt;
  296.     }
  297.     }
  298.  
  299.   __argv = (char **) malloc ((__argc + 1) * sizeof (char *));
  300.  
  301.   if (__argv == NULL)
  302.     {
  303.       __argv = argv;        /* failed */
  304.       return -1;
  305.     }
  306.  
  307.  
  308.   /* Pass 2: Build the new commandline.  */
  309.  
  310.   __argc = 1;
  311.   __argv[0] = argv[0];
  312.  
  313.   if (*(__argv[0])++ != '\"')          /* Reformat the program name.  */
  314.     msdos_format_filename (__argv[0]);
  315.  
  316.   for (optind = 1; optind < argc; optind++)
  317.     {
  318.       char **ptr = glob_argvv[optind];
  319.  
  320.       /* Did we perform globbing?  */
  321.  
  322.       if (ptr == (char **) -1 || *ptr == NULL)
  323.     __argv[__argc++] = argv[optind];
  324.       else
  325.     while (*ptr)
  326.       __argv[__argc++] = *ptr++;
  327.     }
  328.  
  329.  
  330.   __argv[__argc] = NULL;        /* terminate */
  331.   free (glob_argvv);            /* cleanup */
  332.  
  333.   return 0;
  334. }
  335.  
  336.  
  337. /* This is for passing strcmp () to qsort ().  */
  338. int
  339. compare (char **s1, char **s2)
  340. {
  341.   return strcmp (*s1, *s2);
  342. }
  343.  
  344. #endif /* WANT_GLOBBING */
  345.  
  346.  
  347. /* Filenames returned by MS-DOS system calls are formatted very ugly:
  348.    all uppercase and backslashes.  Perform some cosmetics.  */
  349.  
  350. #endif __BORLANDC__
  351.  
  352. char *
  353. msdos_format_filename (char *name)
  354. {
  355.   char *p = name;
  356.   while (*p = (*p == '\\') ? '/' : tolower (*p))
  357.     p++;
  358.   return name;
  359. }
  360.  
  361. #ifdef TEST
  362.  
  363. void
  364. main (int argc, char **argv)
  365. {
  366.   if (*++argv)
  367.     {
  368.       printf ("%s", *argv);
  369.       while (*++argv)
  370.     printf (" %s", *argv);
  371.     }
  372.   exit (0);
  373. }
  374.  
  375. #endif /* TEST */
  376.  
  377. /* 
  378.  * Local Variables:
  379.  * mode:C
  380.  * ChangeLog:ChangeLog
  381.  * compile-command:cl -DSMART_SHELL -DTEST _cwild.c glob msd_dir d:\ms\lib\setgarv -link /noe
  382.  * End:
  383.  */
  384.